package utils

import (
	"fmt"
	"log"
	"os"
	"text/template"
	"unicode"

	"gorm.io/gorm"
)

const serviceTemplate = `package service

import (
	"context"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/internal/req/req_sys"
	"go_web/pkg/req"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"math"

	"github.com/fatih/structs"
	"github.com/jinzhu/copier"
	"gorm.io/gen/field"
)

type {{.ModelName}}Service struct{}

// 创建新的 {{.ModelName}}Service
func New{{.ModelName}}Service() *{{.ModelName}}Service {
	return &{{.ModelName}}Service{}
}

// 分页查询
func (*{{.ModelName}}Service) Page(c context.Context, pageReq req_sys.{{.ModelName}}PageReq) (*res.PageRes, error) {
	offset := (pageReq.Page - 1) * pageReq.PageSize
	q := repo_sys.{{.ModelName}}.WithContext(c)

	// 排序处理
	if pageReq.SortField != nil {
		sortField := utils.ConvertToSnakeCase(*pageReq.SortField)
		orderFieldExpr := field.NewUnsafeFieldRaw(sortField)
		if pageReq.SortOrder != nil {
			if *pageReq.SortOrder == "asc" {
				q = q.Order(orderFieldExpr.Asc())
			} else {
				q = q.Order(orderFieldExpr.Desc())
			}
		} else {
			q = q.Order(orderFieldExpr.Asc())
		}
	}

	// 执行分页查询
	list, count, err := q.FindByPage(offset, pageReq.PageSize)
	if err != nil {
		return nil, err
	}

	// 计算总页数
	page := res.PageRes{
		List:     list,
		Total:    count,
		Page:     pageReq.Page,
		PageSize: pageReq.PageSize,
		Pages:    int64(math.Ceil(float64(count) / float64(pageReq.PageSize))),
	}

	return &page, nil
}

// 添加 {{.ModelName}} 已开启事务
func (*{{.ModelName}}Service) Add(c context.Context, addReq req_sys.{{.ModelName}}AddReq) (int64, error) {
	var {{.ModelName}} model_sys.{{.ModelName}}	
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.{{.ModelName}}.WithContext(c)
		err := copier.Copy(&{{.ModelName}}, &addReq)
		if err != nil {
			return err
		}
		err = q.Create(&{{.ModelName}})
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return {{.ModelName}}.ID, nil
}

// 编辑 {{.ModelName}} 已开启事务
func (*{{.ModelName}}Service) Edit(c context.Context, editReq req_sys.{{.ModelName}}EditReq) (int64, error) {
	var result gen.ResultInfo	
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.{{.ModelName}}.WithContext(c).Where(repo_sys.{{.ModelName}}.ID.Eq(editReq.ID))
		{{.ModelName}}, err := q.First()
		if err != nil {
			return err
		}
		err = copier.Copy(&{{.ModelName}}, &editReq)
		if err != nil {
			return err
		}
		result, err = q.Updates(structs.Map({{.ModelName}}))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		if utils.IsOptimisticLockError(err) {
			return -1, nil // 乐观锁报错（版本不一致）
		}
		return 0, err
	}
	return result.RowsAffected, nil
}

// 删除 {{.ModelName}} 已开启事务
func (*{{.ModelName}}Service) Delete(c context.Context, idsReq req.IdsReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := repo_sys.{{.ModelName}}.WithContext(c)
		ids, err := idsReq.ToInt64Slice()
		if err != nil {
			return err
		}
		sysUserList, err := q.Where(repo_sys.SysUser.ID.In(ids...)).Find()
		if err != nil {
			return err
		}
		result, err = q.Delete(sysUserList...)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return result.RowsAffected, nil
}

// 查看 {{.ModelName}} 详情
func (*{{.ModelName}}Service) Detail(c context.Context, userId int64) (*model_sys.{{.ModelName}}, error) {
	q := repo_sys.{{.ModelName}}.WithContext(c)
	{{.ModelName}}, err := q.Where(repo_sys.{{.ModelName}}.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	return {{.ModelName}}, nil
}
`

func ToSnakeCase(s string) string {
	var result []rune
	for i, char := range s {
		// 如果是大写字母并且不是第一个字母，则插入下划线
		if unicode.IsUpper(char) && i > 0 {
			result = append(result, '_')
		}
		// 转为小写字母
		result = append(result, unicode.ToLower(char))
	}
	return string(result)
}

// 生成 service 文件并添加日志输出
func GenerateService(db *gorm.DB, dbName string, modelName *string) error {
	// 记录生成开始
	log.Printf("开始生成 %s 服务...\n", modelName)
	if modelName == nil {
		tableList, err := getTables(db, dbName, nil)
		if err != nil {
			return err
		}
		for i := range tableList {
			tempModelName := toCamelCase(tableList[i].TableName)
			generateServiceFile(&tempModelName)
		}
	} else {
		generateServiceFile(modelName)
	}

	return nil
}

func generateServiceFile(modelName *string) error {
	// 使用模板
	tmpl, err := template.New("service").Parse(serviceTemplate)
	if err != nil {
		log.Printf("模板解析失败: %v\n", err)
		return err
	}

	// 创建服务文件
	fileName := fmt.Sprintf("./dal/service/%s_service.go", ToSnakeCase(*modelName))
	file, err := os.Create(fileName)
	if err != nil {
		log.Printf("文件创建失败: %v\n", err)
		return err
	}
	defer file.Close()

	// 执行模板生成
	err = tmpl.Execute(file, map[string]string{
		"ModelName": *modelName,
	})
	if err != nil {
		log.Printf("模板渲染失败: %v\n", err)
		return err
	}

	// 输出生成成功的日志
	log.Printf("成功生成 %s 服务文件: %s\n", modelName, fileName)
	return nil
}
